<?php
/**
 * Eka Framework 0.3.0
 *
 * @copyright Copyright (c) 2008 Alexey Yu. Chuprina <656b61@gmail.com> (http://php-eka.googlecode.com)
 * @license http://www.opensource.org/licenses/mit-license.php MIT License
 *
 * @version $Id$
 */

/**
 * Eka_Db_Table_Row_Abstract
 *
 * @package Db
 * @subpackage Table
 */
abstract class Eka_Db_Table_Row_Abstract
{

	/**
	 * Data for each column in the row
	 *
	 * @var array
	 */
	protected $data;

	/**
	 * Flags to changed data
	 *
	 * @var array
	 */
	protected $changedData = array();
	
	/**
	 * Where condition for this row
	 *
	 * Primary, unique or all column key-value pairs
	 *
	 * @var array
	 */
	protected $whereCondition;
	
	/**
	 * @var boolean
	 */
	protected $new = false;
	
	/**
	 * @var boolean
	 */
	protected $deleted = false;

	/**
	 * Table object
	 *
	 * @var Eka_Db_Table_Abstract
	 */
	protected $table;

	/**
	 * Constructor
	 *
	 * @param Eka_Db_Table_Abstract $table
	 * @param array $data
	 * @param bool $new
	 */
	public function __construct(Eka_Db_Table_Abstract $table, array $data = null, $new = true)
	{
		$this->table = $table;
		
		$this->data = array_fill_keys($this->table->getColumnNames(), null);
		
		if (null === $data || $new) {
			$this->new = true;
		}
		
		if (null !== $data) {
			$this->data = array_merge($this->data, $data);
		}
		
		$this->updateWhereCondition();
	}

	/**
	 * Retrieve row field value
	 *
	 * @param string $columnName User-specified column name
	 * @return string Сolumn value
	 */
	public function __get($column)
	{
		if (!array_key_exists($column, $this->data)) {
			require_once 'Eka/Db/Table/Row/Exception.php';
			throw new Eka_Db_Table_Row_Exception("Column '$column' is not in the row");
		}
		return $this->data[$column];
	}

	/**
	 * Set row field value
	 *
	 * @param string $column User-specified column name
	 * @param mixed  $value	Value for the property
	 */
	public function __set($column, $value)
	{
		if (!array_key_exists($column, $this->data)) {
			require_once 'Eka/Db/Table/Row/Exception.php';
			throw new Eka_Db_Table_Row_Exception("Column '$column' is not in the row");
		}
		$this->data[$column] = $value;
		$this->changedData[$column] = true;
	}

	/**
	 * Test existence of row field
	 *
	 * @param  string  $columnName   The column key.
	 * @return boolean
	 */
	public function __isset($column)
	{
		return array_key_exists($this->normalizeColumnName($column), $this->data);
	}
	
	/**
	 * Returns the table object
	 *
	 * @return Eka_Db_Table_Abstract
	 */
	public function table()
	{
		return $this->table;
	}

	/**
	 * Saves the properties to the database
	 */
	public function save()
	{
		if ($this->new) {
			$this->insert();
		} else {
			$this->update();
		}
	}
	
	/**
	 * Delete record from DB
	 */
	public function delete()
	{
		if (!$this->new) {
			$this->table->delete($this->getWhereQuery(), null, 1);
			$this->new = true;
			$this->deleted = true;
		}
	}

	/**
	 * insert
	 */
	protected function insert()
	{
		$columns = $this->table->getColumns();
		foreach ($this->data as $col => $val) {
			if (null === $val && !$columns[$col]['null']) {
				$this->data[$col] = $columns[$col]['default'];
			}
		}
		
		$where = $this->table->insert($this->data);
		
		$primary = $this->table()->getPrimary();
		
		if (null === $primary) {
			$where = array();
			foreach ($this->table->getColumnNames() as $col) {
				$where[$col] = $this->data[$col];
			}
			$row = $this->table->fetchOne($where);
		} else {
			if (count($primary) > 1) {
				$where = array();
				foreach ($primary as $col) {
					$where[] = $this->data[$col];
				}
			}
			$row = $this->table->getOne($where);
		}
		
		if (null === $row) {
			require_once 'Eka/Db/Table/Row/Exception.php';
			throw new Eka_Db_Table_Row_Exception("плохо");
		}
		
		$this->data = $row->toArray();
		$this->changedData = array();
		$this->updateWhereCondition();
		$this->new = false;
		if ($this->deleted) {
			$this->deleted = false;
		}
	}
	
	/**
	 * update
	 */
	protected function update()
	{
		$data = array_intersect_key($this->data, $this->changedData);

		if (count($data) > 0) {
			$this->table()->update($data, $this->getWhereQuery(), null, 1);
		}
		
		$this->changedData = array();
	}

	/**
	 * Returns the column/value data as an array
	 *
	 * @return array
	 */
	public function toArray()
	{
		return $this->data;
	}

	/**
	 * Sets all data in the row from an array
	 *
	 * @param array $data
	 */
	public function fromArray(array $data)
	{
		foreach ($data as $name => $value) {
			$this->$name = $value;
		}
	}

	/**
	 * update where condition
	 */
	protected function updateWhereCondition()
	{
		$primary = $this->table->getPrimary();
		if ($primary) {
			foreach ($primary as $column) {
				$this->whereCondition[$column] = $this->data[$column];
			}
		} else {
			$this->whereCondition = $this->data;
		}
	}

	/**
	 * @return array
	 */
	protected function getWhereQuery()
	{
		$adapter = $this->table()->getAdapter();
		$where = array();
		foreach ($this->whereCondition as $column => $value) {
			$column = $adapter->quoteIdentifier($column);
			$where[$column . ' = ?'] = $value;
		}
		return $where;
	}
}
